package labox.innovation.gameserver.model;

import labox.innovation.config.Config;
import labox.innovation.gameserver.idfactory.IdFactory;
import labox.innovation.gameserver.instancemanager.InstanceManager;
import labox.innovation.gameserver.instancemanager.ItemsOnGroundManager;
import labox.innovation.gameserver.model.actor.L2Character;
import labox.innovation.gameserver.model.actor.L2Npc;
import labox.innovation.gameserver.model.actor.instance.FuzePcInstance;
import labox.innovation.gameserver.model.actor.knownlist.ObjectKnownList;
import labox.innovation.gameserver.model.actor.poly.ObjectPoly;
import labox.innovation.gameserver.model.actor.position.ObjectPosition;
import labox.innovation.gameserver.network.L2GameClient;
import labox.innovation.gameserver.network.serverpackets.ActionFailed;

/**
 * 在world中所有类的基础父类，子类可以是 (PC, NPC, Item...)等等<BR><BR>
 *
 * L2Object :<BR><BR>
 * <li>L2Character</li>
 * <li>L2ItemInstance</li>
 * <li>L2Potion</li>
 *
 */

public abstract class L2Object {
	// =========================================================
	// Data Field
	private boolean _isVisible; //对象是否可见

	protected ObjectKnownList _knownList;

	private String _name;

	protected long _objectId; // 对象的ID

	private ObjectPoly _poly;

	protected ObjectPosition _position;//对象的位置对象

	private int _instanceId;

	// =========================================================
	// Constructor
	public L2Object(long objectId) {
		_objectId = objectId;
		initKnownList();
		initPosition();
	}

	// =========================================================
	// Event - Public
	public void onAction(FuzePcInstance player) {
		player.sendPacket(ActionFailed.STATIC_PACKET);
	}

	public void onActionShift(L2GameClient client) {
		client.getActiveChar().sendPacket(ActionFailed.STATIC_PACKET);
	}

	public void onForcedAttack(FuzePcInstance player) {
		player.sendPacket(ActionFailed.STATIC_PACKET);
	}

	// =========================================================
	// Position - Should remove to fully move to L2ObjectPosition
	public final void setXY(int x, int y) {
		_position.setXY(x, y);
	}

	public final void setXYInvisible(int x, int y) {
		_position.setXYInvisible(x, y);
	}

	public final int getX() {
		if (Config.ASSERT)
			assert getPosition().getSceneRegion() != null || _isVisible;
		return getPosition().getX();
	}

	public final int getY() {
		if (Config.ASSERT)
			assert getPosition().getSceneRegion() != null || _isVisible;
		return getPosition().getY();
	}

	/**
	 * @return The id of the instance zone the object is in - id 0 is global
	 * since everything like dropped items, mobs, players can be in a instanciated area, it must be in l2object
	 */
	public int getInstanceId() {
		return _instanceId;
	}

	/**
	 * 设置对象所在的副本ID
	 * @param instanceId The id of the instance zone the object is in - id 0 is global
	 */
	public void setInstanceId(int instanceId) {
		if (_instanceId == instanceId)
			return;

		if (this instanceof FuzePcInstance) {//如果是PC端
			if (_instanceId > 0)
				InstanceManager.getInstance().getInstance(_instanceId).removePlayer(_objectId);
			if (instanceId > 0)
				InstanceManager.getInstance().getInstance(instanceId).addPlayer(_objectId);

			if (((FuzePcInstance) this).getPet() != null)
				((FuzePcInstance) this).getPet().setInstanceId(instanceId);
		} else if (this instanceof L2Npc) {//如果是NPC
			if (_instanceId > 0)
				InstanceManager.getInstance().getInstance(_instanceId).removeNpc(((L2Npc) this).getSpawn());
			if (instanceId > 0)
				InstanceManager.getInstance().getInstance(instanceId).addNpc(((L2Npc) this));
		}

		_instanceId = instanceId;

		// If we change it for visible objects, me must clear & revalidate knownlists
		if (_isVisible && _knownList != null) {
			if (this instanceof FuzePcInstance) {

				// We don't want some ugly looking disappear/appear effects, so don't update
				// the knownlist here, but players usually enter instancezones through teleporting
				// and the teleport will do the revalidation for us.
			} else {
				decayMe();
				spawnMe();
			}
		}
	}

	// =========================================================
	// Method - Public
	/**
	 * 从世界的可见区域中删除一个L2Object对象<BR><BR>
	 *
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method DOESN'T REMOVE the object from _allObjects of L2World </B></FONT><BR>
	 * <B><U> Assert </U> :</B><BR><BR>
	 * <li> _worldRegion != null <I>(L2Object is visible at the beginning)</I></li><BR><BR>
	 *
	 * <B><U> Example of use </U> :</B><BR><BR>
	 * <li> Delete NPC/PC or Unsummon</li><BR><BR>
	 *
	 */
	public final void decayMe() {
		if (Config.ASSERT)
			assert getPosition().getScene() != null;
		_isVisible = false;
		FuzeWorld.getInstance().removeVisibleObject(this);
		if (Config.SAVE_DROPPED_ITEM)
			ItemsOnGroundManager.getInstance().removeObject(this);
	}

	/**
	 * 重新获取ID
	 *
	 */
	public void refreshID() {
		FuzeWorld.getInstance().exitWorld(this);
		_objectId = IdFactory.getInstance().getNextId();
		FuzeWorld.getInstance().enterWorld(this);
	}

	/**
	 *在世界的可见场景上的设定的位置出生
	 */
	public final void spawnMe() {
		// Set the x,y position of the L2Object spawn and update its _worldregion
		_isVisible = true;
		FuzeWorld.getInstance().addVisibleObject(this, _position.getScene());
		onSpawn();
	}

	/**
	 *在世界的可见场景的指定位置出生
	 */
	public final void spawnMe(int x, int y) {
		if (Config.ASSERT)
			assert getPosition().getScene() == null;

//		 Set the x,y position of the L2Object spawn and update its _worldregion
		_isVisible = true;
		getPosition().setScenePosition(x, y);
		FuzeWorld.getInstance().addVisibleObject(this, _position.getScene());

		onSpawn();
	}
	
	/**
	 *在世界的可见场景的指定位置出生
	 */
	public final void spawnMe(int id,int x, int y) {
		if (Config.ASSERT)
			assert getPosition().getScene() == null;

		//Set the x,y position of the L2Object spawn and update its _worldregion
		_isVisible = true;
		getPosition().setScenePosition(x, y);
		FuzeWorld.getInstance().addVisibleObject(this, FuzeWorld.getInstance().getScene(id));
		onSpawn();
	}
	
	/**
	 * Do Nothing.<BR><BR>
	 *
	 * <B><U> Overridden in </U> :</B><BR><BR>
	 * <li> L2GuardInstance :  Set the home location of its L2GuardInstance </li>
	 * <li> L2Attackable    :  Reset the Spoiled flag </li><BR><BR>
	 *
	 */
	public void onSpawn() {
	}

	public void toggleVisible() {
		if (isVisible())
			decayMe();
		else
			spawnMe();
	}

	// =========================================================
	// Method - Private

	// =========================================================
	// Property - Public
	public boolean isAttackable() {
		return false;
	}

	public abstract boolean isAutoAttackable(L2Character attacker);

	public boolean isMarker() {
		return false;
	}

	/**
	 * 返回对象是否可见. <BR><BR>
	 *
	 */
	public final boolean isVisible() {
		//return getPosition().getWorldRegion() != null && _IsVisible;
		return getPosition().getSceneRegion() != null;
	}

	public final void setIsVisible(boolean value) {
		_isVisible = value;
		if (!_isVisible){
			Scene sce=_position.getScene();
			if(sce!=null)
				sce.removeVisibleObject(this);
		}
			
	}

	public ObjectKnownList getKnownList() {
		return _knownList;
	}

	/**
	 * Initializes the KnownList of the L2Object,
	 * is overwritten in classes that require a different knownlist Type.
	 * 
	 * Removes the need for instanceof checks.
	 */
	public void initKnownList() {
		_knownList = new ObjectKnownList(this);
	}

	public final void setKnownList(ObjectKnownList value) {
		_knownList = value;
	}

	public final String getName() {
		return _name;
	}

	public final void setName(String value) {
		_name = value;
	}

	/**
	 * 返回对象的唯一标示符
	 * @return id
	 */
	public final long getObjectId() {
		return _objectId;
	}

	public final ObjectPoly getPoly() {
		if (_poly == null)
			_poly = new ObjectPoly(this);
		return _poly;
	}

	/**
	 * 获取位置对象
	 * @return
	 */
	public ObjectPosition getPosition() {
		return _position;
	}

	/**
	 * 基础的位置对象，如果需要不同的类型的位置对象可以重写此方法
	 * 
	 */
	public void initPosition() {
		_position = new ObjectPosition(this);
	}

	public final void setObjectPosition(ObjectPosition value) {
		_position = value;
	}

	/**
	 * 返回这个对象所在位置的region
	 */
	public Scene getScene() {
		return _position.getScene();
	}

	public FuzePcInstance getActingPlayer() {
		return null;
	}

	/**
	 * Sends the Server->Client info packet for the object.<br><br>
	 * Is Overridden in:
	 * <li>L2AirShipInstance</li>
	 * <li>L2BoatInstance</li>
	 * <li>L2DoorInstance</li>
	 * <li>L2PcInstance</li>
	 * <li>L2StaticObjectInstance</li>
	 * <li>L2Decoy</li>
	 * <li>L2Npc</li>
	 * <li>L2Summon</li>
	 * <li>L2Trap</li>
	 * <li>L2ItemInstance</li>
	 */
	public void sendInfo(FuzePcInstance activeChar) {
	}

	@Override
	public String toString() {
		return "" + getObjectId();
	}
}